﻿Imports System
Imports System.Collections
Imports System.Diagnostics
Imports System.Globalization
Imports System.Reflection
Imports System.Security.Principal
Imports System.Threading
Imports System.Web
Imports System.Web.Services
Imports System.Workflow.Runtime
Imports System.Workflow.Runtime.Hosting

Namespace System.Workflow.Activities
    Public MustInherit Class WorkflowWebService
        Inherits WebService
        ' Methods
        Protected Sub New(ByVal workflowType As Type)
            Me.workflowType = workflowType
        End Sub

        Private Shared Function GetWorkflowInstanceId(ByRef isActivation As Boolean) As Guid
            Dim empty As Guid = Guid.Empty
            Dim obj2 As Object = HttpContext.Current.Items.Item("__WorkflowInstanceId__")
            If ((obj2 Is Nothing) AndAlso Not isActivation) Then
                Throw New InvalidOperationException(SR.GetString("Error_NoInstanceInSession"))
            End If
            If (Not obj2 Is Nothing) Then
                empty = DirectCast(obj2, Guid)
                Dim obj3 As Object = HttpContext.Current.Items.Item("__IsActivationContext__")
                If (Not obj3 Is Nothing) Then
                    isActivation = CBool(obj3)
                    Return empty
                End If
                isActivation = False
                Return empty
            End If
            If isActivation Then
                empty = Guid.NewGuid
                HttpContext.Current.Items.Item("__WorkflowInstanceId__") = empty
            End If
            Return empty
        End Function

        Protected Function Invoke(ByVal interfaceType As Type, ByVal methodName As String, ByVal isActivation As Boolean, ByVal parameters As Object()) As Object()
            Dim handler3 As EventHandler([Of] WorkflowCompletedEventArgs) = Nothing
            Dim objArray As Object()
            Dim workflowInstanceId As Guid = WorkflowWebService.GetWorkflowInstanceId((isActivation))
            Dim key As New EventQueueName(interfaceType, methodName)
            Dim method As MethodInfo = interfaceType.GetMethod(methodName)
            Dim responseRequired As Boolean = (Not method.ReturnType Is GetType(Void))
            If Not responseRequired Then
                Dim info2 As ParameterInfo
                For Each info2 In method.GetParameters
                    If (info2.ParameterType.IsByRef OrElse info2.IsOut) Then
                        responseRequired = True
                        Exit For
                    End If
                Next
            End If
            Dim methodMessage As MethodMessage = WorkflowWebService.PrepareMessage(interfaceType, methodName, parameters, responseRequired)
            Dim handler As EventHandler([Of] WorkflowTerminatedEventArgs) = Nothing
            Dim handler2 As EventHandler([Of] WorkflowCompletedEventArgs) = Nothing
            Try 
                Dim workflow As WorkflowInstance
                Dim class3 As <>c__DisplayClass3
                Dim CS$<>8__locals4 As <>c__DisplayClass3 = class3
                If isActivation Then
                    workflow = Me.WorkflowRuntime.CreateWorkflow(Me.workflowType, Nothing, workflowInstanceId)
                    WorkflowWebService.SafeEnqueueItem(workflow, key, methodMessage)
                    workflow.Start
                Else
                    workflow = Me.WorkflowRuntime.GetWorkflow(workflowInstanceId)
                    WorkflowWebService.SafeEnqueueItem(workflow, key, methodMessage)
                End If
                Dim workflowTerminated As Boolean = False
                handler = Function (ByVal sender As Object, ByVal e As WorkflowTerminatedEventArgs) 
                    If e.WorkflowInstance.InstanceId.Equals(CS$<>8__locals4.workflowInstanceId) Then
                        CS$<>8__locals4.methodMessage.SendException(e.Exception)
                        workflowTerminated = True
                    End If
                End Function
                If (handler3 Is Nothing) Then
                    handler3 = Function (ByVal sender As Object, ByVal e As WorkflowCompletedEventArgs) 
                        If e.WorkflowInstance.InstanceId.Equals(workflowInstanceId) Then
                            methodMessage.SendException(New ApplicationException(SR.GetString(CultureInfo.CurrentCulture, "Error_WorkflowCompleted")))
                        End If
                    End Function
                End If
                handler2 = handler3
                AddHandler Me.WorkflowRuntime.WorkflowTerminated, handler
                AddHandler Me.WorkflowRuntime.WorkflowCompleted, handler2
                Dim service As ManualWorkflowSchedulerService = Me.WorkflowRuntime.GetService([Of] ManualWorkflowSchedulerService)
                If (Not service Is Nothing) Then
                    service.RunWorkflow(workflow.InstanceId)
                End If
                If Not responseRequired Then
                    Return New Object(0  - 1) {}
                End If
                Dim message As IMethodResponseMessage = methodMessage.WaitForResponseMessage
                If (Not message.Exception Is Nothing) Then
                    If Not workflowTerminated Then
                        Throw message.Exception
                    End If
                    Throw New ApplicationException(SR.GetString(CultureInfo.CurrentCulture, "Error_WorkflowTerminated"), message.Exception)
                End If
                If (Not message.OutArgs Is Nothing) Then
                    Return DirectCast(message.OutArgs, ArrayList).ToArray
                End If
                objArray = New Object(0  - 1) {}
            Finally
                If (Not handler Is Nothing) Then
                    RemoveHandler Me.WorkflowRuntime.WorkflowTerminated, handler
                End If
                If (Not handler2 Is Nothing) Then
                    RemoveHandler Me.WorkflowRuntime.WorkflowCompleted, handler2
                End If
            End Try
            Return objArray
        End Function

        Private Shared Function PrepareMessage(ByVal interfaceType As Type, ByVal operation As String, ByVal parameters As Object(), ByVal responseRequired As Boolean) As MethodMessage
            Dim name As String = Nothing
            Dim identity As IIdentity = Thread.CurrentPrincipal.Identity
            Dim identity2 As WindowsIdentity = [TryCast](identity,WindowsIdentity)
            If ((Not identity2 Is Nothing) AndAlso (Not identity2.User Is Nothing)) Then
                name = identity2.User.Translate(GetType(NTAccount)).ToString
            ElseIf (Not identity Is Nothing) Then
                name = identity.Name
            End If
            Return New MethodMessage(interfaceType, operation, parameters, name, responseRequired)
        End Function

        Private Shared Sub SafeEnqueueItem(ByVal instance As WorkflowInstance, ByVal key As EventQueueName, ByVal message As MethodMessage)
        Label_0000:
            Try 
                instance.EnqueueItem(key, message, Nothing, Nothing)
            Catch exception1 As WorkflowOwnershipException
                WorkflowActivityTrace.Activity.TraceEvent(TraceEventType.Warning, 0, String.Format(CultureInfo.InvariantCulture, "Workflow Web Host Encountered Workflow Instance Ownership conflict for instanceid {0}.", New Object() { instance.InstanceId }))
                Thread.Sleep(500)
                goto Label_0000
            End Try
        End Sub


        ' Properties
        Friend Shared ReadOnly Property CurrentWorkflowRuntime As WorkflowRuntime
            Get
                If (WorkflowWebService.wRuntime Is Nothing) Then
                    SyncLock WorkflowWebService.wRuntimeSync
                        If (WorkflowWebService.wRuntime Is Nothing) Then
                            Dim runtime As New WorkflowRuntime("WorkflowRuntime")
                            Try 
                                runtime.StartRuntime
                            Catch obj1 As Object
                                runtime.Dispose
                                Throw
                            End Try
                            Thread.MemoryBarrier
                            WorkflowWebService.wRuntime = runtime
                        End If
                    End SyncLock
                End If
                Return WorkflowWebService.wRuntime
            End Get
        End Property

        Protected ReadOnly Property WorkflowRuntime As WorkflowRuntime
            Get
                If (Not HttpContext.Current Is Nothing) Then
                    Return WorkflowWebService.CurrentWorkflowRuntime
                End If
                Return Nothing
            End Get
        End Property


        ' Fields
        Friend Const ConfigSectionName As String = "WorkflowRuntime"
        Private workflowType As Type
        Private Shared wRuntime As WorkflowRuntime
        Private Shared wRuntimeSync As Object = New Object
    End Class
End Namespace

